import os
import logging
import logging.handlers
import sys
import time
import datetime


class MyTimedRotatingFileHandler(logging.handlers.TimedRotatingFileHandler):
    def shouldRollover(self, record):
        return False


class Logger(object):
    def __init__(self):
        self._format = None
        self._get_frame = getattr(sys, '_getframe')

    def init_logger(self, warning_filename, info_filename, error_filename):
        self._warning_filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), warning_filename)
        self._info_filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), info_filename)
        self._error_filename = os.path.join(os.path.dirname(os.path.abspath(__file__)), error_filename)
        self._format = logging.Formatter(f"[%(mytime)s][%(levelname)s] %(myfile)s:%(myline)d => %(message)s")
        self._warning_logger = logging.getLogger("warning")
        self._info_logger = logging.getLogger("info")
        self._error_logger = logging.getLogger("error")
        self._warning_logger.setLevel(logging.WARNING)
        self._info_logger.setLevel(logging.INFO)
        self._error_logger.setLevel(logging.ERROR)
        self._add_stream_handler()
        self._add_file_handler()

    def _add_stream_handler(self):
        warning_handler = logging.StreamHandler()
        warning_handler.setLevel(logging.WARNING)
        warning_handler.setFormatter(self._format)
        self._warning_logger.addHandler(warning_handler)
        info_handler = logging.StreamHandler()
        info_handler.setLevel(logging.INFO)
        info_handler.setFormatter(self._format)
        self._info_logger.addHandler(info_handler)
        error_handler = logging.StreamHandler()
        error_handler.setLevel(logging.ERROR)
        error_handler.setFormatter(self._format)
        self._error_logger.addHandler(info_handler)

    def _add_file_handler(self):
        warning_handler = MyTimedRotatingFileHandler(
            self._warning_filename, when='midnight', interval=1, backupCount=360, encoding='utf8'
        )
        warning_handler.setLevel(logging.WARNING)
        warning_handler.setFormatter(self._format)
        self._warning_logger.addHandler(warning_handler)
        info_handler = MyTimedRotatingFileHandler(
            self._info_filename, when='midnight', interval=1, backupCount=360, encoding='utf8'
        )
        info_handler.setLevel(logging.INFO)
        info_handler.setFormatter(self._format)
        self._info_logger.addHandler(info_handler)
        error_handler = MyTimedRotatingFileHandler(
            self._error_filename, when='midnight', interval=1, backupCount=360, encoding='utf8'
        )
        error_handler.setLevel(logging.ERROR)
        error_handler.setFormatter(self._format)
        self._error_logger.addHandler(error_handler)

    def _get_caller(self, depth=0):
        """
        获取调用者所在文件名和行号
        :return:
        """
        now = time.strftime('%Y-%m-%d %H:%M:%S')
        msec = (time.time() - int(time.time())) * 1000
        mytime = '%s,%03d' % (now, msec)

        # user: 2->logger.info: 1->logger._get_caller: 0
        frame = self._get_frame(depth + 2)
        filename = os.path.split(frame.f_code.co_filename)[1]
        return {"myfile": filename, "myline": frame.f_lineno, "mytime": mytime}

    def warning(self, msg, depth=0, *args, **kwargs):
        self._warning_logger.warning(msg, *args, **kwargs, extra=self._get_caller(depth))

    def info(self, msg, *args, depth=0, **kwargs):
        self._info_logger.info(msg, *args, **kwargs, extra=self._get_caller(depth))

    def error(self, msg, *args, depth=0, **kwargs):
        self._error_logger.error(msg, *args, **kwargs, extra=self._get_caller(depth))


logger = Logger()
date = datetime.datetime.today().strftime("%Y-%m-%d")
project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
project_name = os.path.basename(project_path)
logger.init_logger(f"{project_path}/logs/{date}-{project_name}-warning.log",
                   f"{project_path}/logs/{date}-{project_name}-info.log",
                   f"{project_path}/logs/{date}-{project_name}-error.log"
                   )


